package com.zhentao.face;




import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.zhentao.utils.FileUtil;
import com.zhentao.utils.HttpUtil;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * 人脸比对 WebAPI 接口调用示例
 * 运行前：请先填写Appid、APIKey、APISecret以及图片路径
 * 运行方法：直接运行 main() 即可
 * 结果： 控制台输出结果信息
 * 接口文档（必看）：https://www.xfyun.cn/doc/face/xffaceComparisonRecg/API.html
 * @author iflytek
 */

@RestController
@RequestMapping("/api/face")
public class WebFaceCompare {

    private static final Gson gson = new Gson();

    // 配置常量（建议后续移至 application.yml）
    private static final String APP_ID = "3b3a0ac1";
    private static final String API_SECRET = "Y2ZjMWVjZDRmZDFiNDBjMzI1OWNiM2Nk";
    private static final String API_KEY = "8aed4a773576595b588349dc41245d42";
    private static final String REQUEST_URL = "https://api.xf-yun.com/v1/private/s67c9c78c";
    private static final String SERVICE_ID = "s67c9c78c";

    /**
     * 人脸比对REST接口
     * @param image1 第一张图片路径或URL
     * @param image2 第二张图片路径或URL
     * @return 比对结果（含相似度分数）
     */
    @PostMapping("/compare")
    public Map<String, Object> compareFacesRest(
            @RequestParam("image1") String image1,
            @RequestParam("image2") String image2) {
        return compareFaces(image1, image2);
    }

    /**
     * 人脸比对服务方法（供其他服务调用）
     * @param image1 第一张图片路径或URL
     * @param image2 第二张图片路径或URL
     * @return 比对结果（含相似度分数）
     */
    public Map<String, Object> compareFaces(String image1, String image2) {

        Map<String, Object> response = new HashMap<>();

        try {
            ResponseData result = faceContrast(image1, image2);

            if (result == null || result.getPayLoad() == null || result.getPayLoad().getFaceCompareResult() == null) {
                response.put("code", 500);
                response.put("message", "人脸比对失败：无返回结果");
                return response;
            }

            String textBase64 = result.getPayLoad().getFaceCompareResult().getText();
            if (textBase64 == null || textBase64.isEmpty()) {
                response.put("code", 500);
                response.put("message", "人脸比对失败：返回数据为空");
                return response;
            }

            String text = new String(Base64.getDecoder().decode(textBase64), "UTF-8");
            JsonObject textJson = gson.fromJson(text, JsonObject.class);

            int ret = textJson.get("ret").getAsInt();
            if (ret != 0) {
                response.put("code", 500);
                response.put("message", "引擎内部错误，ret=" + ret);
                return response;
            }

            float score = textJson.get("score").getAsFloat();

            response.put("code", 200);
            response.put("message", "比对成功");
            response.put("score", score);
            response.put("isSamePerson", score >= 0.67); // 建议阈值

        } catch (Exception e) {
            e.printStackTrace();
            response.put("code", 500);
            response.put("message", "系统异常：" + e.getMessage());
        }

        return response;
    }

    /**
     * 执行人脸比对核心逻辑
     */
    private ResponseData faceContrast(String imageFirstUrl, String imageSecondUrl) throws Exception {
        String url = assembleRequestUrl(REQUEST_URL, API_KEY, API_SECRET);

        byte[] img1Bytes = readImage(imageFirstUrl);
        byte[] img2Bytes = readImage(imageSecondUrl);

        if (img1Bytes == null || img2Bytes == null) {
            throw new IllegalArgumentException("图片读取失败");
        }

        String imageBase641 = Base64.getEncoder().encodeToString(img1Bytes);
        String imageBase642 = Base64.getEncoder().encodeToString(img2Bytes);

        String imageEncoding1 = getImageFormat(imageFirstUrl);
        String imageEncoding2 = getImageFormat(imageSecondUrl);

        String bodyParam = getXParam(imageBase641, imageEncoding1, imageBase642, imageEncoding2);
        return handleFaceContrastRes(url, bodyParam);
    }

    /**
     * 构建请求体参数
     */
    private String getXParam(String imageBase641, String imageEncoding1, String imageBase642, String imageEncoding2) {
        JsonObject jso = new JsonObject();

        // header
        JsonObject header = new JsonObject();
        header.addProperty("app_id", APP_ID);
        header.addProperty("status", 3);
        jso.add("header", header);

        // parameter
        JsonObject parameter = new JsonObject();
        JsonObject service = new JsonObject();
        service.addProperty("service_kind", "face_compare");

        JsonObject faceCompareResult = new JsonObject();
        faceCompareResult.addProperty("encoding", "utf8");
        faceCompareResult.addProperty("format", "json");
        faceCompareResult.addProperty("compress", "raw");
        service.add("face_compare_result", faceCompareResult);
        parameter.add(SERVICE_ID, service);
        jso.add("parameter", parameter);

        // payload
        JsonObject payload = new JsonObject();

        JsonObject inputImage1 = new JsonObject();
        inputImage1.addProperty("encoding", imageEncoding1);
        inputImage1.addProperty("image", imageBase641);
        payload.add("input1", inputImage1);

        JsonObject inputImage2 = new JsonObject();
        inputImage2.addProperty("encoding", imageEncoding2);
        inputImage2.addProperty("image", imageBase642);
        payload.add("input2", inputImage2);

        jso.add("payload", payload);
        return jso.toString();
    }

    /**
     * 读取图片（支持本地路径或HTTP URL）
     */
    private byte[] readImage(String imagePath) throws IOException {
        if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
            URL url = new URL(imagePath);
            try (InputStream is = url.openStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = is.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                return baos.toByteArray();
            }
        } else {
            return FileUtil.read(imagePath);
        }
    }

    /**
     * 获取图片格式（从路径或URL提取扩展名）
     */
    private String getImageFormat(String path) {
        String lower = path.toLowerCase();
        if (lower.endsWith(".png")) return "png";
        if (lower.endsWith(".bmp")) return "bmp";
        if (lower.endsWith(".jpeg")) return "jpeg";
        return "jpg"; // 默认
    }

    /**
     * 发送HTTP请求并解析响应
     */
    private ResponseData handleFaceContrastRes(String url, String bodyParam) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json; charset=utf-8");

        String result = HttpUtil.doPost2(url, headers, bodyParam);
        if (result != null) {
            return gson.fromJson(result, ResponseData.class);
        }
        return null;
    }

    /**
     * 组装带鉴权参数的请求URL
     */
    private static String assembleRequestUrl(String requestUrl, String apiKey, String apiSecret) {
        try {
            String httpRequestUrl = requestUrl.replace("ws://", "http://").replace("wss://", "https://");
            URL url = new URL(httpRequestUrl);

            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());

            String host = url.getHost();
            if (url.getPort() != -1 && url.getPort() != 80 && url.getPort() != 443) {
                host = host + ":" + url.getPort();
            }

            StringBuilder builder = new StringBuilder("host: ").append(host).append("\n")
                    .append("date: ").append(date).append("\n")
                    .append("POST ").append(url.getPath()).append(" HTTP/1.1");

            Charset charset = Charset.forName("UTF-8");
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "HmacSHA256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
            String sha = Base64.getEncoder().encodeToString(hexDigits);

            String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                    apiKey, "hmac-sha256", "host date request-line", sha);
            String authBase64 = Base64.getEncoder().encodeToString(authorization.getBytes(charset));

            return String.format("%s?authorization=%s&host=%s&date=%s",
                    requestUrl,
                    URLEncoder.encode(authBase64, "UTF-8"),
                    URLEncoder.encode(host, "UTF-8"),
                    URLEncoder.encode(date, "UTF-8"));

        } catch (Exception e) {
            throw new RuntimeException("组装请求URL失败: " + e.getMessage(), e);
        }
    }

    // ========== 响应数据结构 ========== //
    public static class ResponseData {
        private Header header;
        private PayLoad payload;

        public Header getHeader() { return header; }
        public PayLoad getPayLoad() { return payload; }
    }

    public static class Header {
        private int code;
        private String message;
        private String sid;

        public int getCode() { return code; }
        public String getMessage() { return message; }
        public String getSid() { return sid; }
    }

    public static class PayLoad {
        private FaceResult face_compare_result;

        public FaceResult getFaceCompareResult() { return face_compare_result; }
    }

    public static class FaceResult {
        private String compress;
        private String encoding;
        private String format;
        private String text;

        public String getCompress() { return compress; }
        public String getEncoding() { return encoding; }
        public String getFormat() { return format; }
        public String getText() { return text; }
    }
}
